/*
*
* Copyright (c) 2011 Vaulting Systems International
* 
* Permission is hereby granted, free of charge, to any person obtaining a copy 
* of this software and associated documentation files (the "Software"), to deal 
* in the Software without restriction, including without limitation the rights 
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 
* of the Software, and to permit persons to whom the Software is furnished to do  
* so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all  
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE  
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
package com.ekeyman.ws;

import java.math.BigInteger;

import javax.xml.datatype.DatatypeConfigurationException;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.util.Assert;
import org.springframework.ws.server.endpoint.annotation.Endpoint;
import org.springframework.ws.server.endpoint.annotation.PayloadRoot;

import com.ekeyman.service.EkeymanService;
import com.ekeyman.shared.schema.CreateEncryptionKeysRequest;
import com.ekeyman.shared.schema.CreateEncryptionKeysResponse;
import com.ekeyman.shared.schema.DeleteEncryptionKeysRequest;
import com.ekeyman.shared.schema.DeleteEncryptionKeysResponse;
import com.ekeyman.shared.schema.DeleteUserRequest;
import com.ekeyman.shared.schema.DeleteUserResponse;
import com.ekeyman.shared.schema.DeleteVendorRequest;
import com.ekeyman.shared.schema.DeleteVendorResponse;
import com.ekeyman.shared.schema.GenerateNewPrivateKeyRequest;
import com.ekeyman.shared.schema.GenerateNewPrivateKeyResponse;
import com.ekeyman.shared.schema.GetEncryptionKeysRequest;
import com.ekeyman.shared.schema.GetEncryptionKeysResponse;
import com.ekeyman.shared.schema.GetUserRequest;
import com.ekeyman.shared.schema.GetUserResponse;
import com.ekeyman.shared.schema.GetVendorProfileRequest;
import com.ekeyman.shared.schema.GetVendorProfileResponse;
import com.ekeyman.shared.schema.RegisterAppDeviceRequest;
import com.ekeyman.shared.schema.RegisterAppDeviceResponse;
import com.ekeyman.shared.schema.RegisterUserRequest;
import com.ekeyman.shared.schema.RegisterUserResponse;
import com.ekeyman.shared.schema.RegisterVendorRequest;
import com.ekeyman.shared.schema.RegisterVendorResponse;
import com.ekeyman.shared.schema.UpdateVendorRequest;
import com.ekeyman.shared.schema.UpdateVendorResponse;
import com.ekeymanlib.dto.AppDeviceApiKeys;
import com.ekeymanlib.dto.EncryptionKeys;
import com.ekeymanlib.dto.VendorProfile;


/**
 * Endpoint that handles the Vendor Client Web Service messages using JAXB2 marshalling.
 *
 * @author James Bell
 */
@Endpoint
public class EkeymanEndpoint implements EkeymanWebServiceConstants {

    private static final Log logger = LogFactory.getLog(EkeymanEndpoint.class);

    private final EkeymanService ekeymanService;

    public EkeymanEndpoint(EkeymanService ekeymanService) {
        Assert.notNull(ekeymanService, "vendorClientService must not be null");
        this.ekeymanService = ekeymanService;
    }

    @PayloadRoot(localPart = CREATE_ENCRYPTION_KEYS_REQUEST, namespace = MESSAGES_NAMESPACE)
    public CreateEncryptionKeysResponse createEncryptionKeys(CreateEncryptionKeysRequest request) throws DatatypeConfigurationException {
        
    	if (logger.isDebugEnabled()) {
            logger.debug("Received CreateEncryptionKeysRequest for resource:'" + request.getResourceUri());
    	}
        
    	EncryptionKeys encryptionKeys =  ekeymanService.createEncryptionKeys(
		   request.getResourceUri(), 
		   request.getPublicKey(), 
		   request.getKeyBytesLength().intValue(), 
		   request.getIvBytesLength().intValue(), 
		   request.getSaltBytesLength().intValue(), 
		   request.getIterationCountMax().intValue(),
    	   request.getLocation(), 
    	   request.getDigitalSignature());
    
        CreateEncryptionKeysResponse response = new CreateEncryptionKeysResponse();
        
        response.setKeyBytes(encryptionKeys.getKeyBytes());
        response.setSaltBytes(encryptionKeys.getSaltBytes());
        response.setIvBytes(encryptionKeys.getIvBytes());
        response.setIterationCount(BigInteger.valueOf(encryptionKeys.getIterationCount()));
        
        return response;
    }
    
    @PayloadRoot(localPart = GET_ENCRYPTION_KEYS_REQUEST, namespace = MESSAGES_NAMESPACE)
    public GetEncryptionKeysResponse getEncryptionKeys(GetEncryptionKeysRequest request) throws DatatypeConfigurationException {
        
    	if (logger.isDebugEnabled()) {
            logger.debug("Received GetEncryptionKeysRequest for resource:'" + request.getResourceUri());
    	}
        
    	EncryptionKeys encryptionKeys =  ekeymanService.getEncryptionKeys(
		   request.getResourceUri(), 
		   request.getPublicKey(), 
    	   request.getLocation(), 
    	   request.getDigitalSignature());
    
        GetEncryptionKeysResponse response = new GetEncryptionKeysResponse();
        
        response.setKeyBytesLength(BigInteger.valueOf(encryptionKeys.getKeyBytesLength()));
        response.setKeyBytes(encryptionKeys.getKeyBytes());
        response.setSaltBytes(encryptionKeys.getSaltBytes());
        response.setSaltBytesLength(BigInteger.valueOf(encryptionKeys.getSaltBytesLength()));
        response.setIvBytes(encryptionKeys.getIvBytes());
        response.setIvBytesLength(BigInteger.valueOf(encryptionKeys.getIvBytesLength()));
        response.setIterationCount(BigInteger.valueOf(encryptionKeys.getIterationCount()));
        return response;
    }
    
    @PayloadRoot(localPart = DELETE_ENCRYPTION_KEYS_REQUEST, namespace = MESSAGES_NAMESPACE)
    public DeleteEncryptionKeysResponse deleteEncryptionKeys(DeleteEncryptionKeysRequest request) throws DatatypeConfigurationException {
        
    	if (logger.isDebugEnabled()) {
            logger.debug("Received GetEncryptionKeysRequest for resource:'" + request.getResourceUri());
    	}
        
    	ekeymanService.deleteEncryptionKeys(
		   request.getResourceUri(), 
		   request.getPublicKey(), 
    	   request.getLocation(), 
    	   request.getDigitalSignature());
    
        DeleteEncryptionKeysResponse response = new DeleteEncryptionKeysResponse();
        
        response.setOperationSuccessful(true);
        
        return response;
    }
    
    @PayloadRoot(localPart = REGISTER_VENDOR_REQUEST, namespace = MESSAGES_NAMESPACE)
    public RegisterVendorResponse registerVendor(RegisterVendorRequest request) throws DatatypeConfigurationException {
        
    	if (logger.isDebugEnabled()) {
            logger.debug("Received RegisterVendorRequest for resource:'" + request.getName());
    	}
        
    	String apiKey = ekeymanService.registerVendor(
		   request.getName(), 
		   request.getAddress(), 
    	   request.getCity(), 
    	   request.getState(),
		   request.getZip(), 
		   request.getPhone(), 
    	   request.getEmailAddress()  	
    	);
    
    	RegisterVendorResponse response = new RegisterVendorResponse();
        
        response.setApiKey(apiKey);
        
        return response;
    }
    
    @PayloadRoot(localPart = UPDATE_VENDOR_REQUEST, namespace = MESSAGES_NAMESPACE)
    public UpdateVendorResponse updateVendor(UpdateVendorRequest request) throws DatatypeConfigurationException {
        
    	if (logger.isDebugEnabled()) {
            logger.debug("Received UpdateVendorRequest for resource:'" + request.getName());
    	}
        
    	ekeymanService.updateVendor(
    		request.getApiKey(),
			request.getName(), 
			request.getAddress(), 
	    	request.getCity(), 
	    	request.getState(),
			request.getZip(), 
			request.getPhone(), 
	    	request.getEmailAddress()  	
    		);
    
    	UpdateVendorResponse response = new UpdateVendorResponse();
        
        response.setOperationSuccessful(true);
        
        return response;
    }
    
    @PayloadRoot(localPart = DELETE_VENDOR_REQUEST, namespace = MESSAGES_NAMESPACE)
    public DeleteVendorResponse deleteVendor(DeleteVendorRequest request) throws DatatypeConfigurationException {
        
    	if (logger.isDebugEnabled()) {
            logger.debug("Received DeleteVendorRequest for apiKey:'" + request.getApiKey());
    	}
        
    	ekeymanService.deleteVendor(request.getApiKey());
    
    	DeleteVendorResponse response = new DeleteVendorResponse();
        
        response.setOperationSuccessful(true);
        
        return response;
    }
 
    @PayloadRoot(localPart = GET_VENDOR_PROFILE_REQUEST, namespace = MESSAGES_NAMESPACE)
    public GetVendorProfileResponse getVendorProfile(GetVendorProfileRequest request) throws DatatypeConfigurationException {
        
    	if (logger.isDebugEnabled()) {
            logger.debug("Received GetVendorProfileRequest for apiKey:'" + request.getApiKey());
    	}
        
    	VendorProfile vendorProfile = ekeymanService.getVendorProfile(request.getApiKey());
    
    	GetVendorProfileResponse response = new GetVendorProfileResponse();
        
    	response.setName(vendorProfile.getName()); 
    	response.setAddress(vendorProfile.getAddress()); 
    	response.setCity(vendorProfile.getCity()); 
    	response.setState(vendorProfile.getState());
    	response.setZip(vendorProfile.getZip()); 
    	response.setPhone(vendorProfile.getPhone()); 
    	response.setEmailAddress(vendorProfile.getEmailAddress()); 

        
        return response;
    }

    @PayloadRoot(localPart = REGISTER_APP_DEVICE_REQUEST, namespace = MESSAGES_NAMESPACE)
    public RegisterAppDeviceResponse registerAppDevice(RegisterAppDeviceRequest request) throws DatatypeConfigurationException {
        
    	if (logger.isDebugEnabled()) {
            logger.debug("Received RegisterAppDeviceRequest for resource:'" + request.getApplication() + " " + request.getDevice());
    	}
        
    	AppDeviceApiKeys appDeviceApiKeys = ekeymanService.registerAppDevice(
    			request.getApiKey(), request.getApplication(), request.getDevice());
    
    	RegisterAppDeviceResponse response = new RegisterAppDeviceResponse();
        
    	response.setPublicKey(appDeviceApiKeys.getPublicKey()); 
    	response.setPrivateKey(appDeviceApiKeys.getPrivateKey());  
        
        return response;
    }
   
    @PayloadRoot(localPart = GENERATE_NEW_PRIVATEKEY_REQUEST, namespace = MESSAGES_NAMESPACE)
    public GenerateNewPrivateKeyResponse generateNewPrivateKey(GenerateNewPrivateKeyRequest request) throws DatatypeConfigurationException {
        
    	if (logger.isDebugEnabled()) {
            logger.debug("Received GenerateNewPrivateKey for resource:'" + request.getPublicKey());
    	}
        
    	AppDeviceApiKeys appDeviceApiKeys = ekeymanService.generateNewPrivateKey(request.getPublicKey(), request.getApiKey());
     
    	GenerateNewPrivateKeyResponse response = new GenerateNewPrivateKeyResponse();
        
    	response.setPrivateKey(appDeviceApiKeys.getPrivateKey());  
        
        return response;
    }
    
    @PayloadRoot(localPart = REGISTER_USER_REQUEST, namespace = MESSAGES_NAMESPACE)
    public RegisterUserResponse registerUser(RegisterUserRequest request) throws DatatypeConfigurationException {
        
    	if (logger.isDebugEnabled()) {
            logger.debug("Received registerUser for Openidurl:'" + request.getOpenidurl());
    	}
        
    	ekeymanService.registerUser(request.getApiKey(), request.getOpenidurl());
    
    	RegisterUserResponse response = new RegisterUserResponse();
        
    	response.setOperationSuccessful(true); 
        
        return response;
    }
    
    @PayloadRoot(localPart = DELETE_USER_REQUEST, namespace = MESSAGES_NAMESPACE)
    public DeleteUserResponse deleteUser(DeleteUserRequest request) throws DatatypeConfigurationException {
        
    	if (logger.isDebugEnabled()) {
            logger.debug("Received registerUser for Openidurl:'" + request.getOpenidurl());
    	}
        
    	ekeymanService.deleteUser(request.getOpenidurl());
    
    	DeleteUserResponse response = new DeleteUserResponse();
        
    	response.setOperationSuccessful(true); 
        
        return response;
    }
    
    @PayloadRoot(localPart = GET_USER_REQUEST, namespace = MESSAGES_NAMESPACE)
    public GetUserResponse getUser(GetUserRequest request) throws DatatypeConfigurationException {
        
    	if (logger.isDebugEnabled()) {
            logger.debug("Received getUser for Openidurl:'" + request.getOpenidurl());
    	}
        
    	String apiKey = ekeymanService.getUser(request.getOpenidurl());
    
    	GetUserResponse response = new GetUserResponse();
        
    	response.setApiKey(apiKey);
        
        return response;
    }
}
